
#ifndef  RECOVERY_BLOCK_H
#define  RECOVERY_BLOCK_H
#include <stdexcept>
#include <new>

namespace recovery {

//internal use
struct InternalBlock {
    static InternalBlock * allocate(size_t bytes){
        InternalBlock * ret = reinterpret_cast<InternalBlock*>(malloc(bytes));
        new (ret)InternalBlock();
        return ret;
    }
    static void deallocate(InternalBlock * block){
        if(block != nullptr){
            block->~InternalBlock();
        }
        ::free((void*)(block));
    }
    //NOTE: no boundcheck
    unsigned char & data(const size_t index) {
        return reinterpret_cast<unsigned char*>(this)[index];
    }
    const unsigned char & data(const size_t index) const {
        return reinterpret_cast<const unsigned char*>(this)[index];
    }
    unsigned char * addr(const size_t index){
        return reinterpret_cast<unsigned char*>(this) + index;
    }
    const unsigned char * addr(const size_t index) const{
        return reinterpret_cast<const unsigned char*>(this) + index;
    }
    InternalBlock() {}
    ~InternalBlock(){}
private:
};


class Block {
public:
    static const size_t kBlockSize = 4096;

    Block(size_t length = 1)
    : _bytes(length* kBlockSize)
    , block(InternalBlock::allocate(_bytes))
    {
    }
    ~Block(){
        if(block != nullptr){
            InternalBlock::deallocate(block);
            block = nullptr;
        }
    }


    unsigned char & data(const size_t index = 0){
        if(index >= 0 && index < _bytes){
            return block->data(index);
        }
        throw std::out_of_range("index out of range");
    }
    const unsigned char & data(const size_t index = 0) const {
        if(index >= 0 && index < _bytes){
            return block->data(index);
        }
        throw std::out_of_range("index out of range");
    }

    size_t len() const{
        return _bytes / kBlockSize;
    }

    unsigned char * addr(const size_t index = 0){
        if(index >= 0 && index < _bytes){
            return block->addr(index);
        }
        return nullptr;
    }
    const unsigned char * addr(const size_t index = 0) const{
        if(index >= 0 && index < _bytes){
            return block->addr(index);
        }
        return nullptr;
    }
    size_t bytes() const{
        return _bytes;
    }

private:
    const size_t _bytes;
    InternalBlock* block;
};

/*
class BlockView {
public:
	BlockView(Block & block)
	: _block(block)
	, _writeIndex(0)
	, _readIndex(0)
	{
	}

	//void rewind();
	size_t used() const {
		return _writeIndex - _readIndex;
	}
	//TODO: 
	size_t write(const uint8_t * buf, const size_t bytes){
		return 0;
	}
	size_t read(uint8_t * buf, const size_t size){
		return 0;
	}

private:
	Block & _block;
	size_t _writeIndex;
	size_t _readIndex;
};*/

}// end of namespace recovery

#endif   /* RECOVERY_BLOCK_H */
